scalebutton: Don't derive from GtkButton
authorMatthias Clasen <mclasen@redhat.com>
Fri, 10 Apr 2020 00:24:23 +0000 (20:24 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 10 Apr 2020 00:43:45 +0000 (20:43 -0400)
Make GtkScaleButton a widget that has a toggle button
as a child, just like all the other button widgets now.
The immediate benefit of this arrangement is to avoid
the "double focus" problem when we pop up the popup.

Update accessible, demos and tests to match.

demos/widget-factory/widget-factory.c
demos/widget-factory/widget-factory.ui
gtk/a11y/gtkscalebuttonaccessible.c
gtk/a11y/gtkscalebuttonaccessible.h
gtk/gtkscalebutton.c
gtk/ui/gtkscalebutton.ui
gtk/ui/gtkvolumebutton.ui
testsuite/gtk/focus-chain/widget-factory2.tab
testsuite/gtk/focus-chain/widget-factory2.tab-backward

index 0d78b1bb89e496a586ce89c206b7fe0ee27dc445..56088fcca53f26108baf177f050a8521903be2bb 100644 (file)
@@ -442,24 +442,17 @@ on_entry_icon_release (GtkEntry            *entry,
 
 #define EPSILON (1e-10)
 
-static gboolean
-on_scale_button_query_tooltip (GtkWidget  *button,
-                               gint        x,
-                               gint        y,
-                               gboolean    keyboard_mode,
-                               GtkTooltip *tooltip,
-                               gpointer    user_data)
-{
-  GtkScaleButton *scale_button = GTK_SCALE_BUTTON (button);
+static void
+on_scale_button_value_changed (GtkScaleButton *button,
+                               gdouble         value,
+                               gpointer        user_data)
+{
   GtkAdjustment *adjustment;
   gdouble val;
   gchar *str;
-  AtkImage *image;
-
-  image = ATK_IMAGE (gtk_widget_get_accessible (button));
 
-  adjustment = gtk_scale_button_get_adjustment (scale_button);
-  val = gtk_scale_button_get_value (scale_button);
+  adjustment = gtk_scale_button_get_adjustment (button);
+  val = gtk_scale_button_get_value (button);
 
   if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON))
     {
@@ -478,19 +471,10 @@ on_scale_button_query_tooltip (GtkWidget  *button,
       str = g_strdup_printf (C_("volume percentage", "%d %%"), percent);
     }
 
-  gtk_tooltip_set_text (tooltip, str);
-  atk_image_set_image_description (image, str);
-  g_free (str);
+  gtk_widget_set_tooltip_text (GTK_WIDGET (button), str);
+  atk_object_set_description (gtk_widget_get_accessible (GTK_WIDGET (button)), str);
 
-  return TRUE;
-}
-
-static void
-on_scale_button_value_changed (GtkScaleButton *button,
-                               gdouble         value,
-                               gpointer        user_data)
-{
-  gtk_widget_trigger_tooltip_query (GTK_WIDGET (button));
+  g_free (str);
 }
 
 static void
@@ -1774,7 +1758,6 @@ activate (GApplication *app)
   gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
           "on_entry_icon_release", (GCallback)on_entry_icon_release,
           "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed,
-          "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip,
           "on_record_button_toggled", (GCallback)on_record_button_toggled,
           "on_page_combo_changed", (GCallback)on_page_combo_changed,
           "on_range_from_changed", (GCallback)on_range_from_changed,
index 4d8b74e8c8131eae878b6f4d850a8656aff40f44..7e8df2760141a4a9d021c105484fb85e7bef5495 100644 (file)
@@ -1510,7 +1510,6 @@ microphone-sensitivity-medium-symbolic</property>
                                         <property name="valign">center</property>
                                         <property name="value">.5</property>
                                         <property name="halign">center</property>
-                                        <signal name="query-tooltip" handler="on_scale_button_query_tooltip" swapped="no"/>
                                         <signal name="value-changed" handler="on_scale_button_value_changed" swapped="no"/>
                                         <layout>
                                           <property name="left-attach">0</property>
index 1db9db7ba8f0c7f6ef2951c2603f33c67c987c02..98b685382a1632dda0910e1bc6dfc7501216c0dc 100644 (file)
@@ -27,7 +27,7 @@
 static void atk_action_interface_init (AtkActionIface *iface);
 static void atk_value_interface_init  (AtkValueIface  *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GtkScaleButtonAccessible, gtk_scale_button_accessible, GTK_TYPE_BUTTON_ACCESSIBLE,
+G_DEFINE_TYPE_WITH_CODE (GtkScaleButtonAccessible, gtk_scale_button_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
                          G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init));
 
index f5f1d4e17e86b7fa9fbec8d29a08c80b12df1619..2437cda58789fbc9d88484577bf945b4d0a73b4b 100644 (file)
@@ -39,14 +39,14 @@ typedef struct _GtkScaleButtonAccessiblePrivate GtkScaleButtonAccessiblePrivate;
 
 struct _GtkScaleButtonAccessible
 {
-  GtkButtonAccessible parent;
+  GtkWidgetAccessible parent;
 
   GtkScaleButtonAccessiblePrivate *priv;
 };
 
 struct _GtkScaleButtonAccessibleClass
 {
-  GtkButtonAccessibleClass parent_class;
+  GtkWidgetAccessibleClass parent_class;
 };
 
 GDK_AVAILABLE_IN_ALL
index 76c2173d49c16ee0c50b77bc4951c8c8b8b26b77..809e7908578b6d2fb816ddcec6a5b0e74b6bce32 100644 (file)
@@ -39,7 +39,7 @@
 #include "gtkadjustment.h"
 #include "gtkbox.h"
 #include "gtkbuttonprivate.h"
-#include "gtkimage.h"
+#include "gtktogglebutton.h"
 #include "gtkeventcontrollerscroll.h"
 #include "gtkframe.h"
 #include "gtkgesture.h"
@@ -52,6 +52,7 @@
 #include "gtkrangeprivate.h"
 #include "gtkscale.h"
 #include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
 #include "gtkwindowprivate.h"
 #include "gtknative.h"
 
@@ -102,12 +103,13 @@ enum
 
 typedef struct
 {
+  GtkWidget *button;
+
   GtkWidget *plus_button;
   GtkWidget *minus_button;
   GtkWidget *dock;
   GtkWidget *box;
   GtkWidget *scale;
-  GtkWidget *image;
   GtkWidget *active_button;
 
   GtkOrientation orientation;
@@ -139,9 +141,15 @@ static void     gtk_scale_button_size_allocate  (GtkWidget           *widget,
                                                  int                  width,
                                                  int                  height,
                                                  int                  baseline);
+static void     gtk_scale_button_measure        (GtkWidget           *widget,
+                                                 GtkOrientation       orientation,
+                                                 int                  for_size,
+                                                 int                 *minimum,
+                                                 int                 *natural,
+                                                 int                 *minimum_baseline,
+                                                 int                 *natural_baseline);
 static void gtk_scale_button_set_orientation_private (GtkScaleButton *button,
                                                       GtkOrientation  orientation);
-static void     gtk_scale_button_clicked        (GtkButton           *button);
 static void     gtk_scale_button_popup          (GtkWidget           *widget);
 static void     gtk_scale_button_popdown        (GtkWidget           *widget);
 static void     cb_button_clicked               (GtkWidget           *button,
@@ -157,10 +165,9 @@ static gboolean gtk_scale_button_scroll_controller_scroll (GtkEventControllerScr
                                                            gdouble                   dy,
                                                            GtkScaleButton           *button);
 
-G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_BUTTON,
+G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_WIDGET,
                          G_ADD_PRIVATE (GtkScaleButton)
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
-                                                NULL))
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
 
 static guint signals[LAST_SIGNAL] = { 0, };
 
@@ -169,7 +176,6 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
 
   gobject_class->constructed = gtk_scale_button_constructed;
   gobject_class->finalize = gtk_scale_button_finalize;
@@ -177,9 +183,11 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
   gobject_class->set_property = gtk_scale_button_set_property;
   gobject_class->get_property = gtk_scale_button_get_property;
 
+  widget_class->measure = gtk_scale_button_measure;
   widget_class->size_allocate = gtk_scale_button_size_allocate;
+  widget_class->focus = gtk_widget_focus_child;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
 
-  button_class->clicked = gtk_scale_button_clicked;
 
   /**
    * GtkScaleButton:orientation:
@@ -326,19 +334,19 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class,
                                               "/org/gtk/libgtk/ui/gtkscalebutton.ui");
 
+  gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, button);
   gtk_widget_class_bind_template_child_internal_private (widget_class, GtkScaleButton, plus_button);
   gtk_widget_class_bind_template_child_internal_private (widget_class, GtkScaleButton, minus_button);
   gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, dock);
   gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, box);
   gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, scale);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, image);
 
   gtk_widget_class_bind_template_callback (widget_class, cb_button_clicked);
   gtk_widget_class_bind_template_callback (widget_class, cb_scale_value_changed);
   gtk_widget_class_bind_template_callback (widget_class, cb_popup_mapped);
 
   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_BUTTON_ACCESSIBLE);
-  gtk_widget_class_set_css_name (widget_class, I_("button"));
+  gtk_widget_class_set_css_name (widget_class, I_("scalebutton"));
 }
 
 static gboolean
@@ -373,6 +381,28 @@ button_pressed_cb (GtkGesture     *gesture,
   priv->autoscroll_timeout = g_timeout_add (200, start_autoscroll, button);
 }
 
+static void
+gtk_scale_button_toggled (GtkScaleButton *button)
+{
+  GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
+  gboolean active;
+
+  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
+
+  if (active)
+    gtk_popover_popup (GTK_POPOVER (priv->dock));
+  else
+    gtk_popover_popdown (GTK_POPOVER (priv->dock));
+}
+
+static void
+gtk_scale_button_closed (GtkScaleButton *button)
+{
+  GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE);
+}
+
 static void
 gtk_scale_button_init (GtkScaleButton *button)
 {
@@ -399,6 +429,11 @@ gtk_scale_button_init (GtkScaleButton *button)
                     button);
   gtk_widget_add_controller (GTK_WIDGET (button), controller);
 
+  g_signal_connect_swapped (priv->dock, "closed",
+                            G_CALLBACK (gtk_scale_button_closed), button);
+  g_signal_connect_swapped (priv->button, "toggled",
+                            G_CALLBACK (gtk_scale_button_toggled), button);
+
   g_signal_connect (gtk_button_get_gesture (GTK_BUTTON (priv->plus_button)),
                     "pressed", G_CALLBACK (button_pressed_cb), button);
   g_signal_connect (gtk_button_get_gesture (GTK_BUTTON (priv->minus_button)),
@@ -505,6 +540,7 @@ gtk_scale_button_dispose (GObject *object)
   GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
 
   g_clear_pointer (&priv->dock, gtk_widget_unparent);
+  g_clear_pointer (&priv->button, gtk_widget_unparent);
 
   if (priv->click_id != 0)
     {
@@ -722,43 +758,6 @@ gtk_scale_button_get_popup (GtkScaleButton *button)
   return priv->dock;
 }
 
-static void
-apply_orientation (GtkScaleButton *button,
-                   GtkOrientation  orientation)
-{
-  GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
-
-  if (priv->applied_orientation != orientation)
-    {
-      priv->applied_orientation = orientation;
-      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), orientation);
-
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        {
-          gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->plus_button, NULL);
-          gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->scale, NULL);
-        }
-      else
-        {
-          gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->scale, NULL);
-          gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->plus_button, NULL);
-        }
-
-      gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->scale), orientation);
-
-      if (orientation == GTK_ORIENTATION_VERTICAL)
-        {
-          gtk_widget_set_size_request (GTK_WIDGET (priv->scale), -1, SCALE_SIZE);
-          gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
-        }
-      else
-        {
-          gtk_widget_set_size_request (GTK_WIDGET (priv->scale), SCALE_SIZE, -1);
-          gtk_range_set_inverted (GTK_RANGE (priv->scale), FALSE);
-        }
-    }
-}
-
 static void
 gtk_scale_button_set_orientation_private (GtkScaleButton *button,
                                           GtkOrientation  orientation)
@@ -798,34 +797,13 @@ gtk_scale_button_scroll_controller_scroll (GtkEventControllerScroll *scroll,
  * button callbacks.
  */
 
-static gboolean
+static void
 gtk_scale_popup (GtkWidget *widget)
 {
   GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
   GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
-  GtkWidget *toplevel;
-  GtkBorder border;
-  GtkRequisition req;
-  gint w, h;
-  gint size;
-
-  gtk_popover_popup (GTK_POPOVER (priv->dock));
-
-  toplevel = GTK_WIDGET (gtk_widget_get_root (widget));
-  _gtk_window_get_shadow_width (GTK_WINDOW (toplevel), &border);
-  w = gtk_widget_get_allocated_width (toplevel) - border.left - border.right;
-  h = gtk_widget_get_allocated_height (toplevel) - border.top - border.bottom;
-  gtk_widget_get_preferred_size (priv->dock, NULL, &req);
-  size = MAX (req.width, req.height);
-
-  if (size > w)
-    apply_orientation (button, GTK_ORIENTATION_VERTICAL);
-  else if (size > h)
-    apply_orientation (button, GTK_ORIENTATION_HORIZONTAL);
-  else
-    apply_orientation (button, priv->orientation);
 
-  return TRUE;
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
 }
 
 static void
@@ -834,13 +812,7 @@ gtk_scale_button_popdown (GtkWidget *widget)
   GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
   GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
 
-  gtk_popover_popdown (GTK_POPOVER (priv->dock));
-}
-
-static void
-gtk_scale_button_clicked (GtkButton *button)
-{
-  gtk_scale_popup (GTK_WIDGET (button));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE);
 }
 
 static void
@@ -918,7 +890,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
 
   if (!priv->icon_list || priv->icon_list[0][0] == '\0')
     {
-      gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), "image-missing");
+      gtk_button_set_icon_name (GTK_BUTTON (priv->button), "image-missing");
       return;
     }
 
@@ -927,7 +899,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
   /* The 1-icon special case */
   if (num_icons == 1)
     {
-      gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), priv->icon_list[0]);
+      gtk_button_set_icon_name (GTK_BUTTON (priv->button), priv->icon_list[0]);
       return;
     }
 
@@ -945,7 +917,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
       else
         name = priv->icon_list[1];
 
-      gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), name);
+      gtk_button_set_icon_name (GTK_BUTTON (priv->button), name);
       return;
     }
 
@@ -968,7 +940,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
       name = priv->icon_list[i];
     }
 
-  gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), name);
+  gtk_button_set_icon_name (GTK_BUTTON (priv->button), name);
 }
 
 static void
@@ -1003,6 +975,26 @@ cb_popup_mapped (GtkWidget *popup,
   gtk_widget_grab_focus (priv->scale);
 }
 
+static void
+gtk_scale_button_measure (GtkWidget      *widget,
+                          GtkOrientation  orientation,
+                          int             for_size,
+                          int            *minimum,
+                          int            *natural,
+                          int            *minimum_baseline,
+                          int            *natural_baseline)
+{
+  GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
+  GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
+
+  gtk_widget_measure (priv->button,
+                      orientation,
+                      for_size,
+                      minimum, natural,
+                      minimum_baseline, natural_baseline);
+
+}
+
 static void
 gtk_scale_button_size_allocate (GtkWidget *widget,
                                 int        width,
@@ -1012,7 +1004,9 @@ gtk_scale_button_size_allocate (GtkWidget *widget,
   GtkScaleButton *button = GTK_SCALE_BUTTON (widget);
   GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button);
 
-  GTK_WIDGET_CLASS (gtk_scale_button_parent_class)->size_allocate (widget, width, height, baseline);
+  gtk_widget_size_allocate (priv->button,
+                            &(GtkAllocation) { 0, 0, width, height },
+                            baseline);
 
   gtk_native_check_resize (GTK_NATIVE (priv->dock));
 }
index 1714b8b1265c4ed767f93f5a6bffd056d02077ef..f7611fa481ded52a8c5e074c057e83f1ddc02e8e 100644 (file)
@@ -1,13 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="gtk40">
-  <template class="GtkScaleButton" parent="GtkButton">
-    <property name="receives-default">1</property>
-    <property name="relief">none</property>
-    <property name="focus-on-click">0</property>
+  <template class="GtkScaleButton" parent="GtkWidget">
     <child>
-      <object class="GtkImage" id="image">
+      <object class="GtkToggleButton" id="button">
+        <property name="receives-default">1</property>
+        <property name="focus-on-click">0</property>
         <property name="icon-name">image-missing</property>
-        <property name="use-fallback">1</property>
+        <property name="relief">none</property>
       </object>
     </child>
   </template>
index 7859505c6cd5684a2bb00072a59efb71a153ad2f..cf0db3ff8694801892722c6b300c1fa37ea1ec30 100644 (file)
@@ -1,17 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="gtk40">
-  <object class="GtkAdjustment" id="adjustment">
-    <property name="upper">1</property>
-    <property name="step-increment">0.02</property>
-    <property name="page-increment">0.2</property>
-  </object>
   <template class="GtkVolumeButton" parent="GtkScaleButton">
-    <property name="receives-default">1</property>
-    <property name="has-tooltip">1</property>
-    <property name="relief">none</property>
-    <property name="focus-on-click">0</property>
-    <property name="orientation">vertical</property>
-    <property name="adjustment">adjustment</property>
+    <property name="adjustment">
+      <object class="GtkAdjustment">
+        <property name="upper">1</property>
+        <property name="step-increment">0.02</property>
+        <property name="page-increment">0.2</property>
+      </object>
+    </property>
     <property name="icons">audio-volume-muted
 audio-volume-high
 audio-volume-low
index 139d7417a8db849baee6eb2b75aae912af143948..6f7a2eb1d7172478fde4cad083e7f3b346b07806 100644 (file)
@@ -1,6 +1,6 @@
 GtkSpinButton GtkText
-GtkVolumeButton
-GtkScaleButton
+GtkToggleButton
+GtkToggleButton
 GtkTextView
 GtkToggleButton
 GtkToggleButton
index 942daff4e9033e962cf2df619c4446cc2231858a..a803ce791f5f71d755b1d1eda87c1c9102f7d3d9 100644 (file)
@@ -30,8 +30,8 @@ GtkToggleButton
 GtkToggleButton
 GtkToggleButton
 GtkTextView
-GtkScaleButton
-GtkVolumeButton
+GtkToggleButton
+GtkToggleButton
 GtkSpinButton GtkText
 GtkToggleButton
 GtkToggleButton